﻿using System;
using System.Windows;
using System.Windows.Input;

namespace EasyPainter.Imaging.Silverlight
{
   public partial class EditableSlider
   {
      public delegate void ValueChangedHandler(double newValue);

      public event ValueChangedHandler ValueChanged;

      readonly bool isInitialized;
      double startValue;
      string displayFormat;
      bool usingCustomDisplayFormat;

      public double Minimum
      {
         get { return (double)GetValue(MinimumProperty); }
         set { SetValue(MinimumProperty, value); }
      }
      public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(EditableSlider), new PropertyMetadata(0.0, OnMinimumMaximumPropertyChanged));

      public double Maximum
      {
         get { return (double)GetValue(MaximumProperty); }
         set { SetValue(MaximumProperty, value); }
      }
      public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(EditableSlider), new PropertyMetadata(10.0, OnMinimumMaximumPropertyChanged));

      public double Value
      {
         get { return (double)GetValue(ValueProperty); }
         set { SetValue(ValueProperty, value); }
      }
      public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(EditableSlider), new PropertyMetadata(3.0, OnValuePropertyChanged));
      
      public string Description
      {
         get { return (string)GetValue(DescriptionProperty); }
         set { SetValue(DescriptionProperty, value); }
      }
      public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(EditableSlider), new PropertyMetadata("Default"));

      public Visibility TextVisibility
      {
         get { return GridText.Visibility; }
         set { GridText.Visibility = value; }
      }

      public string DisplayFormat
      {
         get { return displayFormat; }
         set
         {
            usingCustomDisplayFormat = true;
            if (displayFormat == value) return;
            displayFormat = value;
            UpdateText();
         }
      }

      public EditableSlider()
      {
         displayFormat = "0.00";
         InitializeComponent();
         DataContext = this;
         isInitialized = true;
         SizeChanged += EditableSlider_SizeChanged;
      }

      private void UpdatePercent(double xPos)
      {
         if (xPos < 0) xPos = 0;
         if (xPos > rectBase.ActualWidth)
            xPos = rectBase.ActualWidth;

         rectPercent.Width = xPos;
         var valuePercent = xPos / rectBase.ActualWidth;
         var minimum = Minimum;
         Value = (Maximum - minimum) * valuePercent + minimum;
      }

      private void ChangeDisplayFormatIfNeeded(string newFormat)
      {
         if (usingCustomDisplayFormat) return;
         if (displayFormat == newFormat) return;
         displayFormat = newFormat;
         UpdateText();
      }

      private void UpdateView()
      {
         var minimum = Minimum;
         var maximum = Maximum;
         var valuePercent = (Value - minimum) / (maximum - minimum);
         rectPercent.Width = rectBase.ActualWidth * valuePercent;

         var range = Math.Abs(maximum - minimum);
         if (range >= 40)
         {
            ChangeDisplayFormatIfNeeded("0");
         }
         else if (range >= 10)
         {
            ChangeDisplayFormatIfNeeded("0.0");
         }
         ChangeDisplayFormatIfNeeded(range >= 0.5 ? "0.00" : "0.0000");
      }

      private void UpdateText()
      {
         textValue.Text = Value.ToString(displayFormat);
      }

      private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
         var slider = d as EditableSlider;
         if (slider != null)
         {
            slider.OnValuePropertyChanged(e);
         }
      }

      private void OnValuePropertyChanged(DependencyPropertyChangedEventArgs e)
      {
         var newValue = (double)e.NewValue;
         UpdateView();
         UpdateText();
         if (ValueChanged != null)
         {
            ValueChanged(newValue);
         }
      }

      private static void OnMinimumMaximumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
         var slider = d as EditableSlider;
         if (slider != null)
         {
            slider.OnMinimumMaximumPropertyChanged();
         }
      }

      private void OnMinimumMaximumPropertyChanged()
      {
         UpdateView();
      }

      private void RectBaseManipulationStarted(object sender, ManipulationStartedEventArgs e)
      {
         startValue = e.ManipulationOrigin.X;
         UpdatePercent(startValue);
         e.Handled = true;
      }

      private void RectBaseManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
      {
         UpdatePercent(startValue + e.TotalManipulation.Translation.X);
         e.Handled = true;
      }

      private void RectBaseManipulationDelta(object sender, ManipulationDeltaEventArgs e)
      {
         UpdatePercent(startValue + e.CumulativeManipulation.Translation.X);
         e.Handled = true;
      }

      void EditableSlider_SizeChanged(object sender, SizeChangedEventArgs e)
      {
         if (!isInitialized)
         {
            return;
         }
         UpdateView();
      }
   }
}